/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.repository.adaptor.method.createpropertydefmethod;

import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.api.attr.EnumDVAttribute;
import com.inspur.edp.cef.api.attr.EnumDVStrAttribute;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.EnumIndexType;
import com.inspur.edp.cef.designtime.api.element.GspEnumValue;
import com.inspur.edp.cef.gencommon.CefPropertyInfo;
import com.inspur.edp.cef.gencommon.ReflectionUtils;
import com.inspur.edp.cef.generator.coreGenerator.base.CefCoreGeneratorContext;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.EntityGeneratorContext;
import com.inspur.edp.cef.generator.repository.adaptor.AdapterGenUtils;
import com.inspur.edp.cef.repository.dbcolumninfo.DbColumnInfo;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import org.eclipse.jdt.core.dom.*;

import java.lang.reflect.Method;

public class EntityCreateIntEnumDefMethodGenerator extends BasePropertyCreateDefMethodGenerator {
    private DbColumnInfo dbColumn;
    private IGspCommonField gspCommonField;
    private String propertyName;
//    private CefPropertyInfo propertyType;
    private static final String varName = "obj";
    private CefCoreGeneratorContext cefCoreGeneratorContext;
    private IGspCommonObject gspCommonObject;
    public EntityCreateIntEnumDefMethodGenerator(CefCoreGeneratorContext cefCoreGeneratorContext, DbColumnInfo dbColumn, String propertyName, IGspCommonField gspCommonField, CefPropertyInfo propertyType) {
        this.cefCoreGeneratorContext = cefCoreGeneratorContext;
        this.dbColumn = dbColumn;
        this.propertyName = propertyName;
        this.gspCommonField = gspCommonField;
//        this.propertyType = propertyType;
    }

    private boolean enableStringIndex() {
        return gspCommonField.getEnumIndexType() == EnumIndexType.String;
    }

    private EntityGeneratorContext getEntityContext(){
        EntityGeneratorContext entityGeneratorContext = new EntityGeneratorContext();
        entityGeneratorContext.setProjContext(this.cefCoreGeneratorContext);
        return entityGeneratorContext;
    }

    @Override
    protected Block buildMethodBody() {
        Block block = ast.newBlock();
        if (enableStringIndex()) {
            boolean isString = getEntityContext().getFieldTypeInfo(gspCommonObject.getCode(), gspCommonField).getTypeName().equals("String");
//            boolean isString = (this.propertyType.getPropertyMethod().getReturnType() == String.class);
            VariableDeclarationStatement methodInvocation = AdapterGenUtils.getReadValueStatement(this.ast, "obj", this.propertyName, "reader", isString);
            addReturnDefault(block);
            switch (this.dbColumn.getColumnType()) {
                case VarChar:
                case NVarChar:
                    addStringStatementStr(block);
                    return block;
            }
            throw new RuntimeException("#GSPBefError#" + "不支持数据库字段类型为【" + dbColumn.getColumnType().toString() + "】的枚举字段使用" + "#GSPBefError#");
        }
        else {
            boolean isString = getEntityContext().getFieldTypeInfo(gspCommonObject.getCode(), gspCommonField).getTypeName().equals("String");
//            boolean isString = propertyType.getPropertyMethod().getReturnType() == String.class;
            VariableDeclarationStatement methodInvocation = AdapterGenUtils.getReadValueStatement(ast, varName, propertyName, ParamReader, isString);
            addReturnDefault(block);
            switch (dbColumn.getColumnType()) {
                case Int:
                    addIntStatement(block);
                    break;
                case VarChar:
                case NVarChar:
                    addStringStatement(block);
                    break;
                default:
                    throw new RuntimeException("#GSPBefError#" + "不支持数据库字段类型为【" + dbColumn.getColumnType().toString() + "】的枚举字段使用" + "#GSPBefError#");
            }
        }
//		AddReturnDefaultValue(statements);
//		switch (dbColumn.getColumnType()) {
//			case GSPDbDataType.Int:
//				AddInitStatments(statements);
//				break;
//			case GSPDbDataType.VarChar:
//			case GSPDbDataType.NVarChar:
//				AddStringStatements(statements);
//				break;
//			default:
//				throw new RuntimeException("#GSPBefError#" + "不支持数据库字段类型为【" + dbColumn.getColumnType().toString() + "】的枚举字段使用" + "#GSPBefError#");
//		}
//		return SyntaxFactory.Block(statements.toArray(new StatementSyntax[]{}));
        return block;
    }

    private void addReturnDefault(Block block) {
        IfStatement ifStatement = ast.newIfStatement();
        addReadValueStatement(block);
        addReturnDefaultIfExpression(ifStatement);
        addReturnDefaultIfThen(ifStatement);
        block.statements().add(ifStatement);
    }

    private void addReadValueStatement(Block block) {
        block.statements().add(AdapterGenUtils.getReadValueStatement(ast, "obj", propertyName, ParamReader, false));
    }

    private void addReturnDefaultIfExpression(IfStatement ifStatement) {
//        InfixExpression infixExpression = ast.newInfixExpression();
//        infixExpression.setLeftOperand(ast.newSimpleName("obj"));
//        infixExpression.setOperator(InfixExpression.Operator.EQUALS);
//        infixExpression.setRightOperand(ast.newNullLiteral());
//        ifStatement.setExpression(infixExpression);
        InfixExpression infixExpression = this.ast.newInfixExpression();
        InfixExpression infixExpression1 = this.ast.newInfixExpression();
        infixExpression1.setLeftOperand(this.ast.newSimpleName("obj"));
        infixExpression1.setOperator(InfixExpression.Operator.EQUALS);
        infixExpression1.setRightOperand(this.ast.newNullLiteral());
        infixExpression.setLeftOperand(infixExpression1);
        infixExpression.setOperator(InfixExpression.Operator.CONDITIONAL_OR);
        MethodInvocation methodInvocation = this.ast.newMethodInvocation();
        MethodInvocation methodInvocation1 = this.ast.newMethodInvocation();
        methodInvocation1.setExpression(this.ast.newSimpleName("obj"));
        methodInvocation1.setName(this.ast.newSimpleName("toString"));
        methodInvocation.setExpression(methodInvocation1);
        methodInvocation.setName(this.ast.newSimpleName("equals"));
        StringLiteral stringLiteral = this.ast.newStringLiteral();
        stringLiteral.setLiteralValue("");
        methodInvocation.arguments().add(stringLiteral);
        infixExpression.setRightOperand(methodInvocation);
        ifStatement.setExpression(infixExpression);
    }

    private String getEnumDefaultValue(){
        String defaultValue = "";
        if(gspCommonField.getContainEnumValues() !=null && gspCommonField.getContainEnumValues().size() > 0){
            for (GspEnumValue gspEnumValue:gspCommonField.getContainEnumValues()){
                if(gspEnumValue.getIsDefaultEnum()){
                    return gspEnumValue.getValue();
                }
            }
        }
        return defaultValue;
    }

    private TypeInfo getTypeInfo(){
        return getEntityContext().getFieldTypeInfo(gspCommonObject.getCode(), gspCommonField);
    }

    private void addReturnDefaultIfThen(IfStatement ifStatement) {
//        MethodInvocation methodInvocation = this.ast.newMethodInvocation();
////        methodInvocation.setExpression(this.ast.newName(this.propertyType.getPropertyMethod().getReturnType().getTypeName()));
//        methodInvocation.setExpression(this.ast.newName(getTypeInfo().getTypeName()));
//        methodInvocation.setName(this.ast.newSimpleName("forValue"));
//        if (enableStringIndex()) {
//            StringLiteral stringLiteral = this.ast.newStringLiteral();
//            stringLiteral.setLiteralValue(getEnumDefaultValue());
//            methodInvocation.arguments().add(stringLiteral);
//        } else {
//            NumberLiteral numberLiteral = this.ast.newNumberLiteral();
//            numberLiteral.setToken(getEnumDefaultValue());
//            methodInvocation.arguments().add(numberLiteral);
//        }
//        ReturnStatement returnStatement = this.ast.newReturnStatement();
//        returnStatement.setExpression(methodInvocation);
//        ifStatement.setThenStatement(returnStatement);
        ReturnStatement returnStatement = ast.newReturnStatement();
        returnStatement.setExpression(ast.newNullLiteral());
        ifStatement.setThenStatement(returnStatement);
    }
    private void addStringStatementStr(Block block) {
        MethodInvocation methodInvocation = this.ast.newMethodInvocation();
        methodInvocation.setExpression(this.ast.newName(getTypeInfo().getTypeName()));
        methodInvocation.setName(this.ast.newSimpleName("forValue"));
        CastExpression castExpression = this.ast.newCastExpression();
        castExpression.setType((new TypeInfo("String")).getType(this.ast));
        castExpression.setExpression(this.ast.newSimpleName("obj"));
        methodInvocation.arguments().add(castExpression);
        ReturnStatement returnStatement = this.ast.newReturnStatement();
        returnStatement.setExpression(methodInvocation);
        block.statements().add(returnStatement);
    }
    private void addIntStatement(Block block) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newName(getTypeInfo().getTypeName()));
        methodInvocation.setName(ast.newSimpleName("forValue"));

        MethodInvocation invocation = ast.newMethodInvocation();
        invocation.setExpression(ast.newName(Integer.class.getTypeName()));
        invocation.setName(ast.newSimpleName("parseInt"));
        MethodInvocation arg =  ExpressionUtils.getMethodInvocation(ast, "obj", "toString");
        invocation.arguments().add(arg);

        methodInvocation.arguments().add(invocation);
        ReturnStatement returnStatement = ast.newReturnStatement();
        returnStatement.setExpression(methodInvocation);
        block.statements().add(returnStatement);
    }

    //	return (GspDbDataType)Enum.valueOf(GspDbDataType.class,(String)obj);
    private void addStringStatement(Block block) {

        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newName(getTypeInfo().getTypeName()));
        methodInvocation.setName(ast.newSimpleName("forValue"));

        MethodInvocation invocation = ast.newMethodInvocation();
        invocation.setExpression(ast.newName(Integer.class.getTypeName()));
        invocation.setName(ast.newSimpleName("parseInt"));
        MethodInvocation arg =  ExpressionUtils.getMethodInvocation(ast, "obj", "toString");
        invocation.arguments().add(arg);

        methodInvocation.arguments().add(invocation);
        ReturnStatement returnStatement = ast.newReturnStatement();
        returnStatement.setExpression(methodInvocation);


//		ReturnStatement returnStatement=ast.newReturnStatement();
//		CastExpression castExpression=ast.newCastExpression();
//		castExpression.setType(ast.newSimpleType(ast.newName(propertyType.getPropertyMethod().getReturnType().getTypeName())));
//		addStringCastExpression(castExpression);
//		returnStatement.setExpression(castExpression);
        block.statements().add(returnStatement);
    }

    private void addStringCastExpression(CastExpression castExpression) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("valueOf"));
        methodInvocation.setExpression(ast.newName(Enum.class.getTypeName()));
        TypeLiteral typeLiteral = ast.newTypeLiteral();
        typeLiteral.setType(ast.newSimpleType(ast.newName(getTypeInfo().getTypeName())));
        methodInvocation.arguments().add(typeLiteral);

        CastExpression castExpression1 = ast.newCastExpression();
        castExpression1.setType(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(String.class).getType(ast));
        castExpression1.setExpression(ast.newSimpleName("obj"));
        methodInvocation.setExpression(castExpression1);
        castExpression.setExpression(methodInvocation);

    }

    private String VarString = "str";

    @Override
    protected String getMethodName() {
        return getEnumPropertyValueMethodName(propertyName);
    }

    @Override
    protected TypeInfo getReturnType() {
        return getTypeInfo();
    }

    public static String getEnumPropertyValueMethodName(String propertyName) {
        return String.format("get%1$sEnumPropertyValue", propertyName);
    }
}
